﻿namespace HutongGames.PlayMakerEditor
{
    using HutongGames.PlayMaker;
    using System;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEngine;

    public class FsmLogger : EditorWindow
    {
        private FsmLogEntry afterSelected;
        private bool autoScroll;
        private FsmLogEntry beforeSelected;
        private FsmState currentState;
        private bool dimRemainingEntries;
        private static FsmLogger instance;
        private int numEntriesDrawn;
        private FsmLogEntry prevEntry;
        private Vector2 scrollPosition;
        private float scrollViewHeight;
        private Rect selectedRect;

        private void ClearLog()
        {
            if (SelectedLog != null)
            {
                SelectedLog.Clear();
            }
        }

        private static void ClickEventTarget(FsmLogEntry entry)
        {
            switch (entry.EventTarget.target)
            {
                case FsmEventTarget.EventTarget.Self:
                    break;

                case FsmEventTarget.EventTarget.GameObject:
                {
                    if (entry.Event == null)
                    {
                        break;
                    }
                    List<Fsm> fsmList = FsmInfo.GetFsmList(FsmInfo.FindTransitionsUsingEvent(entry.Event.Name));
                    GenericMenu menu = new GenericMenu();
                    foreach (Fsm fsm in fsmList)
                    {
                        menu.AddItem(new GUIContent(FsmEditorUtility.GetFullFsmLabel(fsm)), false, new GenericMenu.MenuFunction2(FsmEditor.SelectFsm), fsm);
                    }
                    menu.ShowAsContext();
                    return;
                }
                case FsmEventTarget.EventTarget.GameObjectFSM:
                {
                    Fsm fsm2 = FsmEditorUtility.FindFsmOnGameObject(FsmEditor.SelectedFsm.GetOwnerDefaultTarget(entry.EventTarget.gameObject), entry.EventTarget.fsmName.Value);
                    if (fsm2 == null)
                    {
                        break;
                    }
                    FsmEditor.SelectFsm(fsm2);
                    return;
                }
                case FsmEventTarget.EventTarget.FSMComponent:
                    if (entry.EventTarget.fsmComponent == null)
                    {
                        break;
                    }
                    FsmEditor.SelectFsm(entry.EventTarget.fsmComponent.Fsm);
                    return;

                case FsmEventTarget.EventTarget.BroadcastAll:
                    if (entry.Event != null)
                    {
                        List<Fsm> list2 = FsmInfo.GetFsmList(FsmInfo.FindTransitionsUsingEvent(entry.Event.Name));
                        GenericMenu menu2 = new GenericMenu();
                        foreach (Fsm fsm3 in list2)
                        {
                            menu2.AddItem(new GUIContent(FsmEditorUtility.GetFullFsmLabel(fsm3)), false, new GenericMenu.MenuFunction2(FsmEditor.SelectFsm), fsm3);
                        }
                        menu2.ShowAsContext();
                    }
                    break;

                default:
                    return;
            }
        }

        private void ClickSentBy(FsmLogEntry entry)
        {
            if (entry.SentByState != null)
            {
                FsmEditor.SelectFsm(entry.SentByState.Fsm);
                FsmEditor.SelectState(entry.SentByState, true);
            }
        }

        private static void CollapseSystemEvents()
        {
            FsmEditorSettings.LogCollapseSystemEvents = !FsmEditorSettings.LogCollapseSystemEvents;
            FsmEditorSettings.SaveSettings();
            FsmLog.CollapseSystemEvents = FsmEditorSettings.LogCollapseSystemEvents;
        }

        private void DoLogLine(FsmLogEntry entry)
        {
            if (!string.IsNullOrEmpty(entry.Text))
            {
                if ((entry.LogType == FsmLogType.EnterState) || (entry.LogType == FsmLogType.Start))
                {
                    this.currentState = entry.State;
                    FsmEditorGUILayout.Divider(new GUILayoutOption[0]);
                }
                if (this.dimRemainingEntries)
                {
                    GUI.color = new Color(1f, 1f, 1f, 0.3f);
                }
                GUI.backgroundColor = (this.currentState != null) ? Fsm.StateColors[this.currentState.ColorIndex] : Color.grey;
                GUILayout.BeginVertical(FsmEditorStyles.LogBackground, new GUILayoutOption[0]);
                GUILayout.BeginHorizontal(new GUILayoutOption[0]);
                GUIStyle logLine = FsmEditorStyles.GetLogTypeStyles()[(int) entry.LogType];
                GUILayout.Label("", logLine, new GUILayoutOption[] { GUILayout.MaxWidth(20f) });
                logLine = FsmEditorStyles.LogLine;
                if (GUILayout.Button(entry.Text, logLine, new GUILayoutOption[0]))
                {
                    this.SelectLogEntry(entry);
                }
                GUILayout.EndHorizontal();
                if ((FsmEditorSettings.LogShowSentBy && (entry.LogType == FsmLogType.Event)) && (entry.SentByState != entry.State))
                {
                    if (string.IsNullOrEmpty(entry.Text2))
                    {
                        entry.Text2 = "Sent By: " + FsmEditorUtility.GetFullStateLabel(entry.SentByState);
                        if (entry.Action != null)
                        {
                            entry.Text2 = entry.Text2 + " : " + FsmEditorUtility.GetActionLabel(entry.Action);
                        }
                    }
                    if (GUILayout.Button(entry.Text2, FsmEditorStyles.LogLine2, new GUILayoutOption[0]))
                    {
                        this.ClickSentBy(entry);
                    }
                    EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link);
                }
                if ((entry.LogType == FsmLogType.SendEvent) && (entry.EventTarget.target != FsmEventTarget.EventTarget.Self))
                {
                    if (string.IsNullOrEmpty(entry.Text2))
                    {
                        entry.Text2 = "Target: " + this.GetEventTargetLabel(entry.EventTarget);
                    }
                    if (GUILayout.Button(entry.Text2, FsmEditorStyles.LogLine2, new GUILayoutOption[0]))
                    {
                        ClickEventTarget(entry);
                        GUIUtility.ExitGUI();
                        return;
                    }
                    EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link);
                }
                GUILayout.EndVertical();
                if (entry == SelectedEntry)
                {
                    this.beforeSelected = this.prevEntry;
                    GUI.backgroundColor = Color.white;
                    GUILayout.Box(GUIContent.none, FsmEditorStyles.LogLineTimeline, new GUILayoutOption[0]);
                    this.dimRemainingEntries = true;
                }
                if (this.prevEntry == SelectedEntry)
                {
                    this.afterSelected = entry;
                }
                this.prevEntry = entry;
                this.numEntriesDrawn++;
            }
        }

        private static void DoToolbar()
        {
            GUILayout.BeginHorizontal(EditorStyles.toolbar, new GUILayoutOption[0]);
            if (GUILayout.Button(FsmEditorUtility.GetFullFsmLabel(FsmEditor.SelectedFsm), EditorStyles.toolbarDropDown, new GUILayoutOption[0]))
            {
                FsmEditorGUILayout.GenerateFsmSelectionMenu(false).ShowAsContext();
            }
            if (FsmEditorGUILayout.ToolbarSettingsButton())
            {
                GenerateSettingsMenu().ShowAsContext();
            }
            GUILayout.Space(-5f);
            GUILayout.EndHorizontal();
        }

        private static GenericMenu GenerateSettingsMenu()
        {
            GenericMenu menu = new GenericMenu();
            menu.AddItem(new GUIContent("Collapse Repeated System Events"), FsmEditorSettings.LogCollapseSystemEvents, new GenericMenu.MenuFunction(FsmLogger.CollapseSystemEvents));
            menu.AddItem(new GUIContent("Hide Unused Events"), FsmEditorSettings.LogHideUnusedEvents, new GenericMenu.MenuFunction(FsmLogger.HideUnusedEvents));
            menu.AddItem(new GUIContent("Show Sent By"), FsmEditorSettings.LogShowSentBy, new GenericMenu.MenuFunction(FsmLogger.ShowSentBy));
            return menu;
        }

        private string GetEventTargetLabel(FsmEventTarget eventTarget)
        {
            GameObject ownerDefaultTarget;
            switch (eventTarget.target)
            {
                case FsmEventTarget.EventTarget.Self:
                    return null;

                case FsmEventTarget.EventTarget.GameObject:
                    ownerDefaultTarget = FsmEditor.SelectedFsm.GetOwnerDefaultTarget(eventTarget.gameObject);
                    if (ownerDefaultTarget != null)
                    {
                        return (" GameObject: " + ownerDefaultTarget.name);
                    }
                    return " GameObject: None";

                case FsmEventTarget.EventTarget.GameObjectFSM:
                    ownerDefaultTarget = FsmEditor.SelectedFsm.GetOwnerDefaultTarget(eventTarget.gameObject);
                    if (ownerDefaultTarget != null)
                    {
                        return string.Concat(new object[] { " GameObjectFSM: ", ownerDefaultTarget.name, " ", eventTarget.fsmName });
                    }
                    return " GameObjectFSM: None";

                case FsmEventTarget.EventTarget.FSMComponent:
                    if (eventTarget.fsmComponent != null)
                    {
                        return (" FsmComponent: " + FsmEditorUtility.GetFullFsmLabel(eventTarget.fsmComponent.Fsm));
                    }
                    return " FsmComponent: None";

                case FsmEventTarget.EventTarget.BroadcastAll:
                    return " BroadcastAll";
            }
            return null;
        }

        private static void HideUnusedEvents()
        {
            FsmEditorSettings.LogHideUnusedEvents = !FsmEditorSettings.LogHideUnusedEvents;
            FsmEditorSettings.SaveSettings();
        }

        private void KeyboardGUI()
        {
            this.prevEntry = null;
            int controlID = GUIUtility.GetControlID(FocusType.Keyboard);
            if (Event.current.GetTypeForControl(controlID) == EventType.KeyDown)
            {
                switch (Event.current.keyCode)
                {
                    case KeyCode.KeypadEquals:
                        return;

                    case KeyCode.UpArrow:
                        Event.current.Use();
                        this.SelectPreviousLogEntry();
                        GUIUtility.ExitGUI();
                        return;

                    case KeyCode.DownArrow:
                        Event.current.Use();
                        this.SelectNextLogEntry();
                        GUIUtility.ExitGUI();
                        return;
                }
            }
        }

        public void OnDisable()
        {
            if (instance == this)
            {
                instance = null;
            }
        }

        public void OnEnable()
        {
            instance = this;
            base.title = "FSM Log";
            base.minSize = new Vector2(200f, 200f);
            base.autoRepaintOnSceneChange = true;
        }

        public void OnGUI()
        {
            if (FsmEditor.Instance == null)
            {
                base.Close();
            }
            else
            {
                if (EditorApplication.isCompiling)
                {
                    GUI.enabled = false;
                }
                if (!FsmEditorStyles.IsInitialized())
                {
                    FsmEditorStyles.Init();
                }
                EditorGUIUtility.LookLikeControls();
                DoToolbar();
                GUI.enabled = SelectedLog != null;
                this.KeyboardGUI();
                this.currentState = null;
                this.numEntriesDrawn = 0;
                this.dimRemainingEntries = false;
                this.scrollPosition = GUILayout.BeginScrollView(this.scrollPosition, false, true, new GUILayoutOption[0]);
                if ((SelectedLog != null) && (SelectedLog.Entries != null))
                {
                    for (int i = 0; i < SelectedLog.Entries.Count; i++)
                    {
                        FsmLogEntry entry = SelectedLog.Entries[i];
                        if ((entry.LogType == FsmLogType.Event) && FsmEditorSettings.LogHideUnusedEvents)
                        {
                            FsmLogEntry entry2 = (i < (SelectedLog.Entries.Count - 1)) ? SelectedLog.Entries[i + 1] : null;
                            if ((entry2 != null) && (entry2.LogType == FsmLogType.Transition))
                            {
                                this.DoLogLine(entry);
                            }
                        }
                        else
                        {
                            this.DoLogLine(entry);
                        }
                        if (((this.numEntriesDrawn > 0) && (Event.current.type == EventType.Repaint)) && (entry == SelectedEntry))
                        {
                            this.selectedRect = GUILayoutUtility.GetLastRect();
                            this.selectedRect.y -= this.scrollPosition.y;
                        }
                    }
                    if (((this.numEntriesDrawn > 0) && (Event.current.type == EventType.Repaint)) && (SelectedEntry == null))
                    {
                        this.selectedRect = GUILayoutUtility.GetLastRect();
                        this.selectedRect.y -= this.scrollPosition.y;
                    }
                }
                GUILayout.EndScrollView();
                if ((Event.current.type == EventType.Repaint) && this.autoScroll)
                {
                    this.scrollViewHeight = GUILayoutUtility.GetLastRect().height;
                    if (this.selectedRect.y < 0f)
                    {
                        this.scrollPosition.y += this.selectedRect.y;
                        base.Repaint();
                    }
                    else if ((this.selectedRect.y + this.selectedRect.height) > this.scrollViewHeight)
                    {
                        this.scrollPosition.y += (this.selectedRect.y + this.selectedRect.height) - this.scrollViewHeight;
                        base.Repaint();
                    }
                    this.autoScroll = false;
                }
                GUI.enabled = true;
                GUI.backgroundColor = Color.white;
                GUI.color = Color.white;
                GUILayout.BeginHorizontal(EditorStyles.toolbar, new GUILayoutOption[0]);
                if (GUILayout.Button("Clear", EditorStyles.toolbarButton, new GUILayoutOption[0]))
                {
                    this.ClearLog();
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            }
        }

        private void SelectLogEntry(FsmLogEntry entry)
        {
            if (entry != null)
            {
                if (FsmEditorSettings.LogPauseOnSelect && !EditorApplication.isPaused)
                {
                    EditorApplication.isPaused = true;
                }
                DebugFlow.SelectLogEntry(entry, true);
                this.autoScroll = true;
            }
        }

        private void SelectNextLogEntry()
        {
            if ((SelectedEntry != null) && (this.afterSelected != null))
            {
                this.SelectLogEntry(this.afterSelected);
            }
        }

        private void SelectPreviousLogEntry()
        {
            if ((SelectedEntry != null) && (this.beforeSelected != null))
            {
                this.SelectLogEntry(this.beforeSelected);
            }
        }

        private static void ShowSentBy()
        {
            FsmEditorSettings.LogShowSentBy = !FsmEditorSettings.LogShowSentBy;
            FsmEditorSettings.SaveSettings();
        }

        public void Update()
        {
            if (FsmEditor.Instance == null)
            {
                base.Close();
            }
            else if (SelectedLog != null)
            {
                if ((SelectedEntry == null) && (this.selectedRect.y < (this.scrollViewHeight + 100f)))
                {
                    this.autoScroll = true;
                }
                base.Repaint();
            }
        }

        private static FsmLogEntry SelectedEntry
        {
            get
            {
                return DebugFlow.SelectedLogEntry;
            }
        }

        private static FsmLog SelectedLog
        {
            get
            {
                return DebugFlow.SelectedLog;
            }
        }
    }
}

